﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using System.Globalization;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
using Swoosh.Utilities.TraceLogger;
using System.Reflection;
using Swoosh.Contracts.MediaPlayerLib;


namespace Swoosh
{
    
    public static class Program
    {

        [STAThread()]
        public static void Main()
        {

            // Executable Name
            string appProcessName = Path.GetFileNameWithoutExtension(Application.ExecutablePath);

            // Get all Running Processes called the same as the swoosh app
            // I hope at this point that there is no application out there called the same as this one
            Process[] RunningProcesses = Process.GetProcessesByName(appProcessName);
            
            // Only Start the application if not already started.
            if (RunningProcesses.Length <= 1)
            {
                InitializeLogger();

                Logger.Log(LogLevels.Info, "Starting Swoosh!");

                List<Assembly> rawModules = new List<Assembly>();

                if (Directory.Exists(SwooshAppSettings.ApplicationSettings.ModulePath))
                {
                    foreach (string entry in Directory.GetFiles(SwooshAppSettings.ApplicationSettings.ModulePath, "*.dll", SearchOption.AllDirectories))
                    {
                        try
                        {
                            Assembly assembly = Assembly.LoadFrom(entry);

                            foreach (Type type in assembly.GetTypes())
                            {
                                if (type.GetInterface(typeof(IPlaybackDevice).ToString()) != null)
                                {
                                    Logger.Log(LogLevels.Trace, "Loaded module file " + entry);
                                    rawModules.Add(assembly);
                                }
                            }

                        }
                        catch (Exception ex)
                        {
                            Logger.Log(LogLevels.Info, "Unable to load " + entry + ": not a valid assembly");
                            Logger.Log(LogLevels.Trace, ex.ToString());
                        }
                    }
                }
                else
                {
                    Logger.Log(LogLevels.Error, "Invalid Module directory");
                }



                // Load the Configuration File before Applicationstartup
                try
                {
                    XmlDocument xmlDoc = new XmlDocument();
                    xmlDoc.PreserveWhitespace = true;
                    xmlDoc.Load(SwooshAppSettings.ApplicationSettings.ConfigurationFile);

                    XmlNodeList configRawList = xmlDoc.SelectNodes("//SwooshConfig/PlaybackDevices/PlaybackDevice");

                    List<string> tempCfg = new List<string>();

                    foreach (XmlNode singleConfigRaw in configRawList)
                    {
                        XmlNode configNode = singleConfigRaw["Configuration"];
                        singleConfigRaw.RemoveChild(configNode);

                        tempCfg.Add(configNode.InnerXml);
                    }
                    
                    StringReader sr = new StringReader(xmlDoc.InnerXml);
                    
                    SwooshConfig Config = SwooshConfig.DeSerializeConfig(sr);
                    SwooshConfig.CurrentConfig = Config;

                    int i=0;
                    foreach (string cfg in tempCfg)
                    {
                        SwooshConfig.CurrentConfig.PlaybackDevices.ElementAt(i).Configuration = cfg;
                        i++;
                    }

                    foreach (PlaybackDevice player in SwooshConfig.CurrentConfig.PlaybackDevices)
                    {

                        foreach (Assembly rawModule in rawModules)
                        {
                            foreach (Type type in rawModule.GetTypes())
                            {
                                if (type.GetInterface(typeof(IPlaybackDevice).ToString()) != null && type.FullName == player.PlayerClass)
                                {
                                    Logger.Log(LogLevels.Debug, "Initializing player " + player.Name);

                                    IPlaybackDevice newPlayer = (IPlaybackDevice)Activator.CreateInstance(type);

                                    newPlayer.Name = player.Name;
                                    newPlayer.StorageName = player.StorageName;
                                    
                                    XmlDocument tempConfiguration = new XmlDocument();
                                    tempConfiguration.CreateXmlDeclaration("1.0", "utf-16", null);
                                    tempConfiguration.LoadXml(player.Configuration);

                                    newPlayer.LoadConfiguration(tempConfiguration.InnerXml);
                                    SwooshConfig.CurrentConfig.IPlaybackDevices.Add(newPlayer);
                                }
                            }
                        }
                    }

                    foreach (IPlaybackDevice player in SwooshConfig.CurrentConfig.IPlaybackDevices)
                    {
                        Logger.Log(LogLevels.Debug, "Starting player " + player.Name);
                        player.Start();
                    }
                }
                catch (Exception ex)
                {
                    Logger.Log(LogLevels.Error, "Error Loading Configuration.", ex);
                    Logger.Log(LogLevels.Error, "Terminating Swoosh.");
                    return;
                }

                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new MainTray());

                foreach (IPlaybackDevice player in SwooshConfig.CurrentConfig.IPlaybackDevices)
                {
                    Logger.Log(LogLevels.Debug, "Stopping player " + player.Name);
                    player.Stop();
                }

                Logger.Log(LogLevels.Info, "Exiting Swoosh!");
            }

        }

        /// <summary>
        /// Initializes the Logger. If the initialization failes for some reason there is no possibility of Logging it ;) and the application will simply crash with an ugly exception.
        /// </summary>
        public static void InitializeLogger()
        {
            LoggingSettings logSettings = SwooshAppSettings.LoggingSettings;
            string sConsoleLogLevel = logSettings.ConsoleLogLevel;
            string sFileLogLevel = logSettings.FileLogLevel;
            string sEventLogLevel = logSettings.EventLogLevel;
            string sFileLogPath = logSettings.FileLogPath;
            string sFileLogName = logSettings.FileLogName;

            if (!Enum.TryParse<LogLevels>(sConsoleLogLevel, true, out Logger.ConsoleLogLevel))
                Logger.ConsoleLogLevel = LogLevels.Trace;
            if (!Enum.TryParse<LogLevels>(sFileLogLevel, true, out Logger.FileLogLevel))
                Logger.FileLogLevel = LogLevels.Info;
            if (!Enum.TryParse<LogLevels>(sEventLogLevel, true, out Logger.EventLogLevel))
                Logger.EventLogLevel = LogLevels.Warn;

            if (!string.IsNullOrEmpty(sFileLogPath))
                Logger.FileLogPath = sFileLogPath;

            if (!string.IsNullOrEmpty(sFileLogName))
                Logger.FileLogName = sFileLogName;

            Logger.Initialize();
        }

        /// <summary>
        /// Generate a Sample XML Configuration File
        /// </summary>
        //public void GenerateConfig()
        //{
        //    SwooshConfig Config = new SwooshConfig();
        //    Storage bimstorage = new Storage() { Name = "BimStorage" };
        //    Storage benedictusstorage = new Storage() { Name = "BenedictusStorage" };
        //    StorageConverter bimbeneconverter = new StorageConverter()
        //    {
        //        DestinationStorage = "BenedictusStorage",
        //        PrefixTransformation = new List<KeyValuePair<string, string>>() { 
        //            new KeyValuePair<string, string>( "e:\\", "i:\\" ), 
        //            new KeyValuePair<string, string>( "f:\\", "j:\\" ),
        //            new KeyValuePair<string, string>( "g:\\", "k:\\" ), 
        //            new KeyValuePair<string, string>( "h:\\", "l:\\" ), 
        //            new KeyValuePair<string, string>( "l:\\", "d:\\" ), 
        //            new KeyValuePair<string, string>( "m:\\", "e:\\" ), 
        //            new KeyValuePair<string, string>( "n:\\", "f:\\" ) }
        //    };

        //    StorageConverter bimbimconverter = new StorageConverter()
        //    {
        //        DestinationStorage = "BimStorage",
        //        PrefixTransformation = new List<KeyValuePair<string, string>>()
        //    };

        //    StorageConverter benebimconverter = new StorageConverter()
        //    {
        //        DestinationStorage = "BimStorage",
        //        PrefixTransformation = new List<KeyValuePair<string, string>>() { 
        //            new KeyValuePair<string, string>( "i:\\", "e:\\" ), 
        //            new KeyValuePair<string, string>( "j:\\", "f:\\" ), 
        //            new KeyValuePair<string, string>( "k:\\", "g:\\" ), 
        //            new KeyValuePair<string, string>( "l:\\", "h:\\" ), 
        //            new KeyValuePair<string, string>( "d:\\", "l:\\" ), 
        //            new KeyValuePair<string, string>( "e:\\", "m:\\" ), 
        //            new KeyValuePair<string, string>( "f:\\", "n:\\" ) }
        //    };

        //    StorageConverter benebeneconverter = new StorageConverter()
        //    {
        //        DestinationStorage = "BenedictusStorage",
        //        PrefixTransformation = new List<KeyValuePair<string, string>>()
        //    };

        //    bimstorage.Converters.Add(bimbeneconverter);
        //    bimstorage.Converters.Add(bimbimconverter);
        //    benedictusstorage.Converters.Add(benebimconverter);
        //    benedictusstorage.Converters.Add(benebeneconverter);

        //    Config.StorageList.Add(bimstorage);
        //    Config.StorageList.Add(benedictusstorage);

        //    VLCPlayer bimvlc = new VLCPlayer() { Name = "VLCBim", StorageName = "BimStorage", ServerName = "bim", ServerPort = 8080 };
        //    XBMCPlayer benexbmc = new XBMCPlayer() { Name = "XBMCBenedictus", StorageName = "BenedictusStorage", ServerName = "benedictus", ServerPort = 51001 };

        //    Config.VLCPlayers.Add(bimvlc);
        //    Config.XBMCPlayers.Add(benexbmc);

        //    SwooshAction bimtobene = new SwooshAction() { SourcePlayerName = "VLCBim", DestinationPlayerName = "XBMCBenedictus", Trigger = new List<Keys>() { Keys.LControlKey, Keys.LMenu, Keys.NumPad4 } };
        //    SwooshAction benetobim = new SwooshAction() { SourcePlayerName = "XBMCBenedictus", DestinationPlayerName = "VLCBim", Trigger = new List<Keys>() { Keys.LControlKey, Keys.LMenu, Keys.NumPad6 } };

        //    Config.SwooshActionList.Add(bimtobene);
        //    Config.SwooshActionList.Add(benetobim);

        //    SwooshConfig.SerializeConfig(Config);
        //}


    }
}
